/*
===========================================================================

Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 

This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  

Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/
#ifndef __SWF_BITSTREAM_H__
#define __SWF_BITSTREAM_H__

class idSWFBitStream {
public:
					idSWFBitStream();
					idSWFBitStream( const byte * data, uint32 len, bool copy ) { free = false; Load( data, len, copy ); }
					~idSWFBitStream() { Free(); }

	idSWFBitStream & operator=( idSWFBitStream & other );

	void			Load( const byte * data, uint32 len, bool copy );
	void			Free();
	const byte *	Ptr() { return startp; }

	uint32			Length() const { return (uint32)( endp - startp ); }
	uint32			Tell() const { return (uint32)( readp - startp ); }
	void			Seek( int32 offset ) { readp += offset; }
	void			Rewind() { readp = startp; }

	void			ResetBits();

	int				ReadS( unsigned int numBits );
	unsigned int	ReadU( unsigned int numBits );
	bool			ReadBool();

	const byte *	ReadData( int size );

	template< typename T >
	void			ReadLittle( T & val );

	uint8			ReadU8();
	uint16			ReadU16();
	uint32			ReadU32();
	int16			ReadS16();
	int32			ReadS32();
	uint32			ReadEncodedU32();
	float			ReadFixed8();
	float			ReadFixed16();
	float			ReadFloat();
	double			ReadDouble();
	const char *	ReadString();

	void			ReadRect( swfRect_t & rect );
	void			ReadMatrix( swfMatrix_t & matrix );
	void			ReadColorXFormRGBA( swfColorXform_t & cxf );
	void			ReadColorRGB( swfColorRGB_t & color );
	void			ReadColorRGBA( swfColorRGBA_t & color );
	void			ReadGradient( swfGradient_t & grad, bool rgba );
	void			ReadMorphGradient( swfGradient_t & grad );

private:
	bool			free;

	const byte *	startp;
	const byte *	endp;
	const byte *	readp;

	uint64			currentBit;
	uint64			currentByte;

	int				ReadInternalS( uint64 & regCurrentBit, uint64 & regCurrentByte, unsigned int numBits );
	unsigned int	ReadInternalU( uint64 & regCurrentBit, uint64 & regCurrentByte, unsigned int numBits );
};

/*
========================
idSWFBitStream::ResetBits
========================
*/
ID_INLINE void idSWFBitStream::ResetBits() {
	currentBit = 0;
	currentByte = 0;
}

/*
========================
idSWFBitStream::ReadLittle
========================
*/
template< typename T >
void idSWFBitStream::ReadLittle( T & val ) {
	val = *(T *)ReadData( sizeof( val ) );
	idSwap::Little( val );
}

/*
========================
Wrappers for the most basic types
========================
*/
ID_INLINE bool   idSWFBitStream::ReadBool() { return ( ReadU( 1 ) != 0 ); }
ID_INLINE uint8  idSWFBitStream::ReadU8() { ResetBits(); return *readp++; }
ID_INLINE uint16 idSWFBitStream::ReadU16() { ResetBits(); readp += 2; return ( readp[-2] | ( readp[-1] << 8 ) ); }
ID_INLINE uint32 idSWFBitStream::ReadU32() { ResetBits(); readp += 4; return ( readp[-4] | ( readp[-3] << 8 ) | ( readp[-2] << 16 ) | ( readp[-1] << 24 ) ); }
ID_INLINE int16  idSWFBitStream::ReadS16() { ResetBits(); readp += 2; return ( readp[-2] | ( readp[-1] << 8 ) ); }
ID_INLINE int32  idSWFBitStream::ReadS32() { ResetBits(); readp += 4; return ( readp[-4] | ( readp[-3] << 8 ) | ( readp[-2] << 16 ) | ( readp[-1] << 24 ) ); }
ID_INLINE float  idSWFBitStream::ReadFixed8() { ResetBits(); readp += 2; return SWFFIXED8( ( readp[-2] | ( readp[-1] << 8 ) ) ); }
ID_INLINE float  idSWFBitStream::ReadFixed16() { ResetBits(); readp += 4; return SWFFIXED16( ( readp[-4] | ( readp[-3] << 8 ) | ( readp[-2] << 16 ) | ( readp[-1] << 24 ) ) ); }
ID_INLINE float  idSWFBitStream::ReadFloat() { ResetBits(); readp += 4; uint32 i = ( readp[-4] | ( readp[-3] << 8 ) | ( readp[-2] << 16 ) | ( readp[-1] << 24 ) ); return (float &)i; }

ID_INLINE double idSWFBitStream::ReadDouble() {
	const byte * swfIsRetarded = ReadData( 8 );
	byte buffer[8];
	buffer[0] = swfIsRetarded[4];
	buffer[1] = swfIsRetarded[5];
	buffer[2] = swfIsRetarded[6];
	buffer[3] = swfIsRetarded[7];
	buffer[4] = swfIsRetarded[0];
	buffer[5] = swfIsRetarded[1];
	buffer[6] = swfIsRetarded[2];
	buffer[7] = swfIsRetarded[3];
	double d = *(double *)buffer;
	idSwap::Little( d );
	return d;
}

#endif // !__SWF_BITSTREAM_H__
